package org.chimi.rr4s.data;

import java.io.IOException;
import java.util.Date;

import org.apache.log4j.Logger;
import org.chimi.rr4s.domain.Action;
import org.chimi.rr4s.domain.Item;
import org.chimi.rr4s.domain.ItemRepository;
import org.chimi.rr4s.domain.User;
import org.chimi.rr4s.domain.UserRepository;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.MapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.transaction.annotation.Transactional;

/**
 * Initialize for spring integration tests..
 * 
 * @author Choi, Beom Kyun
 * 
 */
public class DataInitializer {
	private Logger logger = Logger.getLogger(getClass());

	@Autowired
	private UserRepository userRepository;
	@Autowired
	private ItemRepository itemRepository;

	private Neo4jTemplate neo4jTemplate;

	@Transactional
	public void init() throws IOException {
		deleteData();
		insertData();
	}

	private void insertData() {
		User USER1 = insertUser("USER1");
		User USER2 = insertUser("USER2");
		User USER3 = insertUser("USER3");
		User USER4 = insertUser("SESSIONID4", "USER4");

		Item ITEM1 = insertItem("ITEM1");
		Item ITEM2 = insertItem("ITEM2");
		Item ITEM3 = insertItem("ITEM3");
		Item ITEM4 = insertItem("ITEM4");

		logger.info("All Users and items are created.");

		relate(USER1, "VIEWED", ITEM1);
		relate(USER2, "VIEWED", ITEM1);
		relate(USER2, "VIEWED", ITEM2);
		relate(USER2, "VIEWED", ITEM3);
		relate(USER2, "VIEWED", ITEM4);
		relate(USER3, "VIEWED", ITEM1);
		relate(USER3, "VIEWED", ITEM2);
		relate(USER3, "VIEWED", ITEM3);
		relate(USER4, "VIEWED", ITEM1);
		relate(USER4, "VIEWED", ITEM2);

		Node referenceNode = neo4jTemplate.getReferenceNode();
		neo4jTemplate.createRelationshipBetween(referenceNode,
				USER1.getPersistentState(), "ROOT", MapUtil.map());
		neo4jTemplate.createRelationshipBetween(referenceNode,
				USER2.getPersistentState(), "ROOT", MapUtil.map());
		neo4jTemplate.createRelationshipBetween(referenceNode,
				USER3.getPersistentState(), "ROOT", MapUtil.map());
		neo4jTemplate.createRelationshipBetween(referenceNode,
				USER4.getPersistentState(), "ROOT", MapUtil.map());
		logger.info("Complete inserting data");
	}

	private void relate(User user, String type, Item item) {
		Action action = neo4jTemplate.createRelationshipBetween(user, item,
				Action.class, type, false);
		action.setActionTime(new Date());
		logger.info(user.getId() + ":" + user.getSessionId() + " relate to "
				+ item.getId() + ":" + item.getType());
	}

	private Item insertItem(String itemId) {
		return itemRepository.save(new Item(itemId, "TYPE"));
	}

	private User insertUser(String userId) {
		return insertUser(null, userId);
	}

	private User insertUser(String sessionId, String userId) {
		return userRepository.save(new User(sessionId, userId));
	}

	/**
	 * delete all data
	 * 
	 * @throws IOException
	 */
	private void deleteData() throws IOException {
		for (Relationship rel : neo4jTemplate.getReferenceNode()
				.getRelationships()) {
			rel.delete();
		}

		ClosableIterable<User> users = userRepository.findAll();
		ClosableIterable<Item> items = itemRepository.findAll();
		for (User user : users) {
			for (Item item : items) {
				Relationship relationship = neo4jTemplate
						.getRelationshipBetween(user, item, "VIEWED");
				if (relationship != null) {
					relationship.delete();
				}
			}
		}
		userRepository.deleteAll();
		itemRepository.deleteAll();
		logger.info("Delete all nodes and relaships!!");
	}

	public void setNeo4jTemplate(Neo4jTemplate neo4jTemplate) {
		this.neo4jTemplate = neo4jTemplate;
	}

}
